﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Diagnostics;
using MovieReview.Models;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using System.Data.Services.Client;


namespace MovieReviews.Controllers
{
    public class MovieController : ApiController
    {
        /*
        * GET /api/movie                    get all movie listings                  GetAllListings
        * GET /api/movie/moviename          get movie by name                       GetMovieByName 
        * GET /api/movie/rating             get movie by rating                     GetMovieByRating   
        * GET /api/movie/date               get movie by date                       GetMovieByDate   
        * GET /api/movie/user               get movie by user                       GetMovieByUser   
        * GET /api/movie/moviename/user     get movie by movie and user             GetMovieAndUser   
        * DELETE /api/movie/user            delete movie listing                    DeleteListing(moviename, reviewer)
        * POST /api/movie                   add movie listing                       PostAddListing(listing)
        * PUT /api/movie                    update rating for a movie listing       PutUpdateListing(listing)
        */

        // use the development storage rather than a specific storage account
        //private static String dataConnectionString = "UseDevelopmentStorage=true";

        // for a real storage account:
        private static String dataConnectionString = "DefaultEndpointsProtocol=https;AccountName=aliciabrowne;AccountKey=xmVnQbVXwf6uSFQjAuppAbu0/vHQwshX57+DI7p4c7j2cYQlu75/S5TCGs0xs7Q2ayH6sutmaoJnIVVJPkmP1A==";
        public static String tableName = "moviereviews";
        public static CloudStorageAccount account = CloudStorageAccount.Parse(dataConnectionString);

        // create the table client
        public static CloudTableClient tableClient = account.CreateCloudTableClient();

        // create the table if it doesn't exist
        public static CloudTable table = tableClient.GetTableReference(tableName);

        // Holds query data
        public static TableQuery<MovieListing> query;

        public MovieController()
        {
        }

        // GET api/movie
        public IEnumerable<MovieListing> GetAllListings()
        {
            List<MovieListing> listings = new List<MovieListing>();
            query = new TableQuery<MovieListing>();        // returns all in table
            foreach (var entity in table.ExecuteQuery(query))
            {
                listings.Add(entity);       // adds every entity in the query to the listings list
            }          
            return listings;                                                   // 200 OK, listings serialized in response body
        }

        // GET api/movie/Inception or api/movie?movie=Inception
        // route template api/{controller}/{moviename} in WebApiConfig.cs
        public IEnumerable<MovieListing> GetMovieByName(String moviename)
        {
            List<MovieListing> listings = new List<MovieListing>();
            // Returns all entitys with moviename given through the function parameters
            query = new TableQuery<MovieListing>().Where(TableQuery.GenerateFilterCondition("MovieName", QueryComparisons.Equal, moviename));   
            foreach (var entity in table.ExecuteQuery(query))
            {
                listings.Add(entity);  // adds every entity in the query to the listings list
            }
            return listings;                                                   // 200 OK, listings serialized in response body
        }

        // GET api/movie/8.9 or api/movie?rating=8.9
        // route template api/{controller}/{rating} in WebApiConfig.cs
        public IEnumerable<MovieListing> GetMovieByRating(Double rating)
        {
            List<MovieListing> listings = new List<MovieListing>();
            // Returns all entitys with rating given through the function parameters
            query = new TableQuery<MovieListing>().Where(TableQuery.GenerateFilterConditionForDouble("Rating", QueryComparisons.GreaterThanOrEqual, rating));        // all
            foreach (var entity in table.ExecuteQuery(query))
            {
                listings.Add(entity);       // adds every entity in the query to the listings list
            }
            return listings;                                                   // 200 OK, listings serialized in response body
        }

        // GET api/movie/01.01.2014 or api/movie?date=01.01.2014
        // route template api/{controller}/{date} in WebApiConfig.cs
        public IEnumerable<MovieListing> GetMovieByDate(DateTime date)
        {
            List<MovieListing> listings = new List<MovieListing>();
            // Returns all entitys with date given through the function parameters
            query = new TableQuery<MovieListing>().Where(TableQuery.GenerateFilterConditionForDate("ReleaseDate", QueryComparisons.GreaterThanOrEqual, date));
            foreach (var entity in table.ExecuteQuery(query))
            {
                listings.Add(entity);          // adds every entity in the query to the listings list
            }
            return listings;
        }

        // GET api/movie/Alice or api/movie?user=Alice
        // route template api/{controller}/{user} in WebApiConfig.cs
        public IEnumerable<MovieListing> GetMovieByUser(String user)
        {
            List<MovieListing> listings = new List<MovieListing>();
            // Returns all entitys with user given through the function parameters
            query = new TableQuery<MovieListing>().Where(TableQuery.GenerateFilterCondition("Reviewer", QueryComparisons.Equal, user));
            foreach (var entity in table.ExecuteQuery(query))
            {
                listings.Add(entity);     // adds every entity in the query to the listings list  
            }
            return listings;            // 200 OK, listings serialized in response body
        }
                   
        // GET api/movie/Inception/Alice or api/movie/Inception?user=Alice
        // route template api/{controller}/{moviename}/{user} in WebApiConfig.cs
        public IEnumerable<MovieListing> GetMovieAndUser(String moviename, String user)
        {
            List<MovieListing> listings = new List<MovieListing>();

            // Returns all entitys with moviename and users given through the function parameters seperately
            String nameFilter = TableQuery.GenerateFilterCondition("MovieName", QueryComparisons.Equal, moviename);
            String userFilter = TableQuery.GenerateFilterCondition("Reviewer", QueryComparisons.Equal, user);
            // Combines above queries
            query = new TableQuery<MovieListing>().Where(TableQuery.CombineFilters(nameFilter, TableOperators.And, userFilter));
            foreach (var entity in table.ExecuteQuery(query))
            {
                listings.Add(entity);    // adds every entity in the query to the listings list   
            }
            return listings;            // 200 OK, listings serialized in response body
        }

        // DELETE api/movie/Inception/Alice
        public void DeleteListing(String moviename, String user)
        {
            // Returns all entitys with moviename and users given through the function parameters seperately
            String nameFilter = TableQuery.GenerateFilterCondition("MovieName", QueryComparisons.Equal, moviename);
            String userFilter = TableQuery.GenerateFilterCondition("Reviewer", QueryComparisons.Equal, user);
            // Combines above queries
            TableQuery<MovieListing> finalFilter = new TableQuery<MovieListing>().Where(TableQuery.CombineFilters(nameFilter, TableOperators.And, userFilter));
            foreach (var entity in table.ExecuteQuery(finalFilter))
            {
                TableOperation deleteOperation = TableOperation.Delete(entity);  // delete found entity
                table.Execute(deleteOperation);
            }
        }

        // POST add new listing MovieListing is the only parameter required.
        public HttpResponseMessage PostAddListing(MovieListing listing)
        {
            if (ModelState.IsValid)                                             // model class validation ok?
            {
                TableOperation addOperation = TableOperation.Insert(listing);       // Insert listing given in function parameters
                table.Execute(addOperation);
                // create http response with Created status code and listing serialised as content and Location header set to URI for new resource
                HttpResponseMessage response = Request.CreateResponse<MovieListing>(HttpStatusCode.Created, listing);
                string uri = Url.Link("DefaultApi", new { moviename = listing.MovieName });         // name of default route in WebApiConfig.cs
                response.Headers.Location = new Uri(uri);                                           // Location URI for newly created resource
                return response;
            }
            else
            {
                throw new HttpResponseException(HttpStatusCode.BadRequest);                 // 400, malformed request
            }
        }

        // PUT update a listing i.e. update the review or rating for specified movielisting
        public void PutUpdateListing(String moviename, String user, MovieListing listing)                  // listing will be in request body
        {
            if (ModelState.IsValid)
            {
                // Returns all entitys with moviename and users given through the function parameters seperately
                String nameFilter = TableQuery.GenerateFilterCondition("MovieName", QueryComparisons.Equal, moviename);
                String userFilter = TableQuery.GenerateFilterCondition("Reviewer", QueryComparisons.Equal, user);
                // Combines above queries
                TableQuery<MovieListing> finalFilter = new TableQuery<MovieListing>().Where(TableQuery.CombineFilters(nameFilter, TableOperators.And, userFilter));
                foreach (var entity in table.ExecuteQuery(finalFilter))
                {
                    TableOperation deleteOperation = TableOperation.Delete(entity); //Delete old entity
                    table.Execute(deleteOperation);
                }
                TableOperation addOperation = TableOperation.Insert(listing);  // Insert new entity
                table.Execute(addOperation);
            }
            else
            {
                throw new HttpResponseException(HttpStatusCode.BadRequest);     // 400, malformed request
            }
        }
    }
}
